grammar Transaction;
import LexUnicode;

transactions: transaction* EOF ;

transaction: (Blanks? NewLine)* transactionHeader transactionEntry+ ;

transactionHeader: Date (Blanks Check)? (Blanks description=DQuoteLiteral)? Blanks? NewLine ;

transactionEntry: Blanks account (Blanks? tags)? Blanks commodity (Blanks items)? (Blanks description=DQuoteLiteral)? Blanks? (NewLine | EOF) ;
account: quoted=SQuoteLiteral | accountName (AccountSeparator accountName)* ;
accountName: Name (Blanks Name)* ;

commodity: Amount (Blanks? Name)? ;

tags: '[' tagList ']' ;
tagList: Blanks? Name Blanks? (',' Blanks? Name Blanks?)* ;

items: '{' itemList '}' ;
itemList: item (',' item)* ;
item: Blanks? commodity Blanks? '@' Blanks? commodity Blanks? ;

LineComment: ';' ~[\r\n]* -> skip ;
Blanks: [ \t]+ ;
NewLine: '\r'? '\n' ;
Date: Digit Digit Digit Digit '-' Digit Digit '-' Digit Digit ;
Check: '?' | '*' ;
AccountSeparator: [|:/\#] ;
Name: UnicodeLetter('-' | '_' | UnicodeLetter | Digit)* ;
Amount: ('+' | '-')? Blanks? (Digit | Digit1 (Digit | '_')* Digit) ('.' Digit+)? ;
DQuoteLiteral: ChineseDQuoteLiteral | EnglishDQuoteLiteral ;
SQuoteLiteral: ChineseSQuoteLiteral | EnglishSQuoteLiteral ;

fragment Digit: [0-9] ;
fragment Digit1: [1-9] ;
fragment HexDigit: [0-9a-fA-F] ;
fragment EscSeq: '\\' ([btnfr"'\\] | UnicodeEsc | . | EOF) ;
fragment UnicodeEsc: 'u' (HexDigit (HexDigit (HexDigit HexDigit?)?)?)? ;
fragment ChineseDQuoteLiteral: '“' (EscSeq | ~ [”\r\n\\])* '”' ;
fragment EnglishDQuoteLiteral: '"' (EscSeq | ~ ["\r\n\\])* '"' ;
fragment ChineseSQuoteLiteral: '‘' (EscSeq | ~ [’\r\n\\])* '’' ;
fragment EnglishSQuoteLiteral: '\'' (EscSeq | ~ ['\r\n\\])* '\'' ;